import asyncio
from tkinter import *
from PIL import Image, ImageTk
import cv2
import features as f
import raspi as r
import time

tk = Tk()
tk.title("人证识别")

# canvas = Canvas(tk, width=400, height=380, bg='#f0f0f0')
canvas = Canvas(tk, width=320, height=480, bg='#f0f0f0')
capture = cv2.VideoCapture(0)
capture.set(3, 320)
capture.set(4, 480)

# 定义提示信息
tip_msg = "人证识别系统 - 初始化"
label = Label(tk, text=tip_msg, fg="black", bg="#ffffff", font=30, pady=10, width=32)
label.pack()

# 人脸模型
face_cascade = cv2.CascadeClassifier('lbpcascade_frontalface.xml')

face_img = cv2.imread('face.jpg')

r.ser_open()

stable = 0
stable_max = 50
working = False
result = False
initial = True
fps = 0
fps_s = 0
show_tmp = 0
strict = 1
time_buffer = time.time()


def com(img_a, sid):
    global result

    if f.compare(img_a, sid):
        result = 1
    else:
        result = 2


while True:
    ret, frame = capture.read()
    frame = cv2.add(frame, face_img)

    if time.time() - time_buffer > 1:
        fps_s = fps
        fps = 0
        time_buffer = time.time()
    else:
        fps = fps + 1

    # 读卡获取学号
    ff = open('xuehao.txt', 'r')
    stu_id = ff.read()

    if stu_id == '':
        tip_msg = '请刷校园卡！'
    else:
        if f.has_pic(stu_id):
            roi_face = frame[100:325, 50:270]
            # 查找人脸（灰度）
            gray = cv2.cvtColor(roi_face, cv2.COLOR_BGR2GRAY)
            faces = face_cascade.detectMultiScale(gray)

            if len(faces):
                r.led_on()
            else:
                r.led_off()

            for (x, y, w, h) in faces:
                font = cv2.FONT_HERSHEY_COMPLEX
                cv2.rectangle(frame, (x + 50, y + 100), (x + 50 + w, y + 100 + h), (123, 104, 238), 2)

                # 当稳定值增加到45时开始识别
                if stable == 4 and not working:
                    r.ser_write("OK!")
                    working = True
                    # 裁剪图像
                    roi = frame[y + 100:y + 100 + h, x + 50:x + 50 + w]
                    # 编码图像
                    img_a_base64 = f.image_to_base64(roi)
                    # 识别图像（多线程非阻塞）
                    loop = asyncio.get_event_loop()
                    loop.run_in_executor(None, com, img_a_base64, stu_id)

            # 当没有人脸时快速降低stable值
            if len(faces) == 0:
                tip_msg = "请移至摄像机框内开始识别"
                if stable > 0:
                    stable -= 1
                else:
                    working = False
                    result = False
            else:
                if stable < 5:
                    stable += 1

            if working:
                tip_msg = "正在识别..."
            else:
                if stable > 2:
                    tip_msg = "请勿移动，正在拍照..."

            # 轮询识别结果
            if result == 1:
                tip_msg = "欢迎：" + stu_id
            elif result == 2:
                tip_msg = "抱歉：人证不匹配"
        else:
            tip_msg = "数据库无此学号，请录入"

    # 显示提示信息
    label.config(text="FPS:" + str(fps_s) + " " + tip_msg)

    if result > 0:
        frame = cv2.blur(frame, (30, 30))

        if strict:
            if result == 1:
                show_temp_s = 1
            else:
                show_temp_s = 0
        else:
            show_temp_s = 1

        if not show_tmp and show_temp_s:
            temp = r.ser_read()
            if temp:
                show_tmp = 1
            else:
                cv2.putText(frame, "Waiting", (50, 380), cv2.FONT_HERSHEY_SIMPLEX, 2, (20, 20, 255), 3)
    else:
        show_tmp = 0

    if show_tmp and show_temp_s:
        cv2.putText(frame, "T: " + str(temp, encoding='utf8'), (50, 380), cv2.FONT_HERSHEY_SIMPLEX, 2, (20, 255, 20), 3)

    img = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
    img = ImageTk.PhotoImage(image=img)
    canvas.create_image((160, 240), image=img)
    canvas.pack()

    if initial:
        initial = False

        intro = "使用方法：\n      将校园卡放置于刷卡器上，屏幕上显示证件对应的“姓名”、“学号”，然后进行人脸识别和体温测量，当人证匹配且体温正常时，门禁可自动打开。"
        intro = Label(tk, text=intro, fg="white", bg="#6495ED", padx=10, pady=10, wraplength=300,
                      justify='left')
        intro.pack()

    # 更新画布
    tk.update()
